﻿#include "udpackclient.h"
#include "clientreadsession.h"
#include "clientwritesession.h"
#include "utils.h"
//#include <netinet/in.h>
#include <winsock.h>
namespace TFTP {

ClientWriteSession *UdpAckClient::findWSession(const TransferInfo &ti)
{
    for(QList<ClientWriteSession*>::iterator it = writes.begin(); it != writes.end(); it++){

        TransferInfo tf = (*it)->transferInfo();
        if (tf == ti)
        {
            return (*it);
        }
    }

    return nullptr;
}


ClientReadSession *UdpAckClient::findRSession(const TransferInfo &ti)
{
    for(QList<ClientReadSession*>::iterator it = reads.begin(); it != reads.end(); it++)
    {
        TransferInfo tf = (*it)->transferInfo();
        if (tf == ti)
        {
            return (*it);
        }
    }
    return nullptr;
}


UdpAckClient::UdpAckClient(const QHostAddress &addr, quint16  port)
    : QObject()
    ,address(addr)
    ,port(port)
{
    socket = new QUdpSocket(this);
    connect(socket, &QUdpSocket::readyRead, this, &UdpAckClient::dataReceived);
}

UdpAckClient::~UdpAckClient()
{
}

void UdpAckClient::dataReceived()
{
    QByteArray buffer;
    qint64 dataLen = socket->pendingDatagramSize();
    buffer.resize(static_cast<int>(dataLen));
    socket->readDatagram(buffer.data(), buffer.size());

    TransferInfo ti(socket, socket->peerAddress(), socket->peerPort());
    switch( ntohs(wordOfArray(buffer)[0]) )
    {
    case ACK: {
        ClientReadSession *rs = findRSession(ti);
        if ( !rs )
        {
            ti.sendError( IllegalOp, "没有上载文件时的ACK数据包");
            return;
        }

        if ( rs->parseAck(buffer) )
        {
            emit sentFile(rs->currentFile(), rs->currentFilename());
            reads.removeOne(rs);
            delete rs;
        }
    } break;
    case DATA: {
        ClientWriteSession *ws = findWSession(ti);
        if ( !ws )
        {
            ti.sendError( IllegalOp, "未下载文件时的数据包");
            return;
        }

        if ( ws->parseData(buffer) )
        {
            emit receivedFile(ws->currentFile(), ws->currentFilename());
            writes.removeOne(ws);
            delete ws;
        }
    } break;
    case ERROR: {
        Session *s = findWSession(ti);
        if (s != nullptr){
            writes.removeOne(reinterpret_cast<ClientWriteSession*>(s));
        }else if ( (s = findRSession(ti) ) )
        {
            reads.removeOne(reinterpret_cast<ClientReadSession*>(s));
        }else{
            qWarning("没有为对方打开会话");
        }

        if ( s )
            qWarning("收到错误数据包，对等会话中止\n%s [%d]",
                        buffer.data() + 4,
                        ntohs(wordOfArray(buffer)[1])
                    );
    } break;
    default:
        ti.sendError(IllegalOp, "非法操作码");
        return;
    }
}


void UdpAckClient::putFile(const QString &localname, const QString &remotename, TransferMode trmode)
{
    reads.push_back( new ClientReadSession(TransferInfo(socket), localname, remotename, trmode) );
}


void UdpAckClient::getFile(const QString &localname, const QString &remotename, TransferMode trmode)
{
    writes.push_back( new ClientWriteSession(TransferInfo(socket), localname, remotename, trmode) );
}

};
